package se.ramfelt.psnfriends.model.web;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;

import se.ramfelt.psn.model.Friend;
import se.ramfelt.psn.web.BadRequestResponseException;
import se.ramfelt.psn.web.ForbiddenResponseException;
import se.ramfelt.psn.web.FriendListRetrievalException;
import se.ramfelt.psn.web.UnauthorizedResponseException;
import se.ramfelt.psn.web.UnexpectedResponseCodeException;
import se.ramfelt.psn.web.us.FriendFactory;
import se.ramfelt.psn.web.us.UsPlaystationSite;
import se.ramfelt.psnfriends.R;

public class PsnCommunicator implements Runnable {
    private final UsPlaystationSite site;
    private final Listener listener;
	private final String username;
	private final String password;
    
    public PsnCommunicator(UsPlaystationSite site, String username, String password, Listener listener) {
        this.username = username;
		this.password = password;
		this.site = site;
        this.listener = listener;
    }

    public void run() {
        try {			
            listener.onStarted(this);
            List<Friend> friends;
            try {
                friends = retrieveFriends(false);
            } catch (FriendListRetrievalException e) {
                friends = retrieveFriends(true);
            }
            listener.onFinished(this, friends);
        } catch (UnknownHostException e) {
            listener.onError(this, R.string.status_psn_unknown_host, e);
        } catch (UnauthorizedResponseException e) {
    		listener.onError(this, R.string.status_psn_login_error, e);
        } catch (ForbiddenResponseException e) {
    		listener.onError(this, R.string.status_psn_server_forbidden, e);
        } catch (BadRequestResponseException e) {
    		listener.onError(this, R.string.status_psn_server_bad_request, e);
        } catch (FriendListRetrievalException e) {
    		listener.onError(this, R.string.status_psn_server_forbidden, e);
        } catch (SocketException e) {
            listener.onError(this, R.string.status_psn_socket_error, e);
        } catch (IOException e) {
            listener.onError(this, R.string.status_psn_io_error, e);
        } catch (UnexpectedResponseCodeException e) {
            listener.onError(this, R.string.status_psn_unexpected_error, e);
        } catch (JSONException e) {
            listener.onError(this, R.string.status_psn_unexpected_error, e);
        } catch (ParseException e) {
            listener.onError(this, R.string.status_psn_unexpected_error, e);
        } catch (Exception e) {
            listener.onError(this, R.string.status_psn_unexpected_error, e); 
        }
    }

    private List<Friend> retrieveFriends(boolean forceLogin) throws MalformedURLException, IOException,
            UnexpectedResponseCodeException, UnauthorizedResponseException, ForbiddenResponseException, BadRequestResponseException, 
            FriendListRetrievalException, JSONException, ParseException {
        if (forceLogin || !site.isLoggedIn()) {
            listener.onStatus(this, R.string.status_psn_login);
            site.login(username, password);
            listener.onStatus(this, R.string.status_psn_loggedin);
        }
        
        listener.onStatus(this, R.string.status_psn_getfriendsxml);
        ArrayList<Friend> list = new ArrayList<Friend>();
        FriendFactory friendFactory = new FriendFactory();
    	for (String name : site.getFriendNames()) {
			list.add(friendFactory.createFriend(site.getFriendSummary(name)));
    	}
        listener.onStatus(this, R.string.status_psn_finished);
        return list;
    }

    public interface Listener {
        void onStarted(PsnCommunicator source);
        void onStatus(PsnCommunicator source, int resourceId);
        void onFinished(PsnCommunicator source, List<Friend> friends);
        void onError(PsnCommunicator source, int resourceId, Throwable t);
    }
}
